/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dao;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import model.Rol;
import model.Rolxusuario;
import model.RolxusuarioId;
import model.Usuario;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

/**
 *
 * @author Silvita
 */
public class UsuarioDAO {
    
    //Session ses;

    /**
     * Se encarga de obtener todos los usuariosTemp que se encuentran en la base de datos.
     * @return {@code List<Usuario>} retorna la lista con usuariosTemp, sino la lista tiene null si no existen usuariosTemp.
     * @throws HibernateException
     * @throws Exception {@code HibernateException} si no se pudo conectar u obtener datos de la base.
     */
    public List<Usuario> obtenerUsuarios() throws HibernateException, Exception{
        List<Usuario> usuarios =null;
        MyFactory mf = new MyFactory();
        Session s = mf.getSf().openSession();
        try {  
            //usuarios = s.createCriteria(Usuario.class).list();
            usuarios = s.createCriteria(Usuario.class).add(Restrictions.eq("activo", /*new Boolean(true)*/true)).list();
        }catch(Exception e){
            throw new Exception("Error: " + e.getMessage());
        }
        finally{
            s.close();
            mf.getSf().close();
        }
        return usuarios;
    }
    
    /**
     * Se encarga de verificar la existencia del usuario proporcionado, junto a la
     * correspondencia de su contraseña, si ambos coinciden retorna {@code true}, otro caso retorna {@code false}
     * @param usu {@code String} nombre de usuario proporcionado
     * @param contra {@code String} contraseña proporcionada
     * @return {@code true} en caso de encontrar el usuario y su contraseña coincida, {@code false} en otro caso
     * @throws Exception {@code HibernateException} si no se pudo conectar u obtener datos de la base
     */
    public boolean verificarUsuario(String usu, String contra) throws Exception{
        
        boolean resp = false;
        List<Usuario> usuarios =null;
        MyFactory mf = new MyFactory();
        Session s = mf.getSf().openSession();
        //ses = mf.getSf().openSession();
        try {  
            usuarios = s.createCriteria(Usuario.class).list();
        }catch(Exception e){
            throw new Exception("Error: " + e.getMessage());
        }
        finally{
            s.close();
            mf.getSf().close();
        }
        
        Usuario temp = new Usuario();
        for(int i = 0;i < usuarios.size();i++){ 
            temp = (Usuario) usuarios.get(i);
            if(temp.getNomUsuario().equals(usu) && temp.getContraUsuario().equals(contra))
                resp=true;
        }
        return resp;
    }
    
    /**
     * Se encarga de devolver el id que corresponde al nombre de usuario (único) que se le envía como
     * parámetro.
     * @param usu {@code String} nombre de usuario proporcionado
     * @return {@code int} que es el id del usuario consultado, {@code 0} si el usuario no existe.
     * @throws Exception {@code HibernateException} si no se pudo conectar u obtener datos de la base.
     */
    public int obtenerIdUsuario(String usu) throws Exception{
        int id=0;
        List<Usuario> usuario=null;
        MyFactory mf = new MyFactory();
        Session s = mf.getSf().openSession();
        try { 
            usuario = s.createCriteria(Usuario.class).add(Restrictions.eq("nomUsuario", new String(usu))).list();
            Usuario temp = new Usuario();
            for(int i = 0;i < usuario.size();i++){ 
                temp = (Usuario) usuario.get(i);
                if(temp.getNomUsuario().equals(usu))
                    id=temp.getIdUsuario();
            }
        }catch(Exception e){
            throw new Exception("Error: " + e.getMessage());
        }
        finally{
            s.close();
            mf.getSf().close();
        }
        
        return id;
    }
    
    
    /**
     * Se encarga de obtener los roles que corresponden a un usuario, dado el id del usuario que se desea
     * consultar.
     * @param id {@code int} id del usuario proporcionado
     * @return {@code string} una cadena, de la forma: "<rol_1>, ... , <rol_N>" , que contiene los roles que pertenecen al usario.
     * @throws Exception {@code HibernateException} si no se pudo conectar u obtener datos de la base.
     */
    public String obtenerRolesDeUsuario(int id) throws Exception{
        List<Rolxusuario> rxu =null;
        String r="";
        
        MyFactory mf = new MyFactory();
        Session s = mf.getSf().openSession();
        
        try {  
            rxu = s.createCriteria(Rolxusuario.class).add(Restrictions.eq("id.idUsuario", new Integer(id))).list();
            Rolxusuario temporal = new Rolxusuario();
            Rol temp2 = new Rol();
            for(int i = 0;i < rxu.size();i++){ 
                temporal = (Rolxusuario) rxu.get(i);
                temp2= (Rol) temporal.getRol();
                if(i==rxu.size()-1)
                    r=r + "\"" +temp2.getNomRol() + "\"";
                else
                    r=r + "\"" +temp2.getNomRol() + "\"" + ",";
            }
        }catch(Exception e){
            throw new Exception("Error: " + e.getMessage());
        }  
        finally{
            s.close();
            mf.getSf().close();
        }
        return r;
    }
    
    /**
     * Permite ingresar un nuevo usuario a la base de datos.
     * @param usu {@code Object Usuario} objeto Usuario donde se guardan todos los datos del usuario a crear.
     * @param usuActivo {@code string} usuario que está logueado en la aplicación en ese momento.
     * @return {@code boolean} true si se pudo insertar el usuario y false si no se pudo insertar.
     * @throws Exception {@code HibernateException} si no se pudo conectar u obtener datos de la base.
     */
    public boolean guardarUsuario(Usuario usu, String usuActivo) throws Exception{
        
        boolean resp=false;
        MyFactory mf = new MyFactory();
        Session s = mf.getSf().openSession();
        //int id=0;
        try{
            Transaction tx = s.beginTransaction();
            /*id=obtenerUltimoId();
            usu.setIdUsuario(id+1);*/
            usu.setUsuCreacionUsuario(usuActivo);
            usu.setFecCreacionUsuario(new Date()); //new Date()
            usu.setUsuModifUsuario(usuActivo);
            usu.setFecModifUsuario(new Date());
            usu.setActivo(true);
            s.save(usu);
            tx.commit();
            resp=true;
        }
        catch(Exception e){
            throw new Exception("Error: " + e.getMessage());
        }  
        finally{
            s.close();
            mf.getSf().close();
        }
        
        return resp;
    }
    
    /**
     * Permite obtener el último id que se encuentra registrado en la tabla de usuariosTemp.
     * @return {@code int} último id registrado.
     * @throws Exception {@code HibernateException} si no se pudo conectar u obtener datos de la base.
     */
    public int obtenerUltimoId() throws Exception{
        int ultId=0;
        List<Usuario> usuario=null;
        MyFactory mf = new MyFactory();
        Session s = mf.getSf().openSession(); 
        try { 
            //usuario = s.createCriteria(Usuario.class).setProjection(Projections.projectionList().add(Projections.max("idUsuario"))).list();
            usuario = s.createCriteria(Usuario.class).list();
            Usuario temp = new Usuario();
            for(int i = 0;i < usuario.size();i++){ 
                temp = (Usuario) usuario.get(i);
                ultId=temp.getIdUsuario();
            }
        }catch(Exception e){
            throw new Exception("Error: " + e.getMessage());
        }
        finally{
            s.close();
            mf.getSf().close();
        }
        return ultId;
    }
    
    /**
     * Permite modificar el usuario indicado. Se debe enviar un objeto usuario con todos los campos
     * seteados, a excepción del usuModifUsuario, fecModifUsuario y el idUsuario.
     * @param usu {@code objec(Usuario)} objeto del tipo Usuario.
     * @param usuActivo {@code string} usuario activo.
     * @return {@code boolean} true si se pudo modificar y false si no se pudo.
     * @throws Exception {@code HibernateException} si no se pudo conectar u obtener datos de la base.
     */
    public boolean modificarUsuario(Usuario usu, String usuActivo) throws Exception{
        
        boolean resp=false;
        MyFactory mf = new MyFactory();
        Session s = mf.getSf().openSession();
        try{
            Transaction tx = s.beginTransaction();
            usu.setUsuModifUsuario(usuActivo);
            usu.setFecModifUsuario(new Date());
            usu.setActivo(true);
            s.update(usu);
            tx.commit();
            resp=true;
        }
        catch(Exception e){
            throw new Exception("Error: " + e.getMessage());
        }  
        finally{
            s.close();
            mf.getSf().close();
        }
        
        return resp;
    }
    
    /**
     * Permite eliminar lógicamente (activo=false) el usuario indicado. Se debe enviar un objeto usuario con 
     * todos los campos seteados, a excepción del usuModifUsuario, fecModifUsuario y el idUsuario.
     * @param usuActivo {@code string} usuario activo.
     * @param id {@code int} id del usuario que se desea eliminar.
     * @return {@code boolean} true si se pudo "eliminar" y false si no se pudo.
     * @throws Exception {@code HibernateException} si no se pudo conectar u obtener datos de la base.
     */
    public boolean eliminarUsuario(String usuActivo,int id) throws Exception{
        
        Usuario usu = obtenerUsuarioPorId(id);
        
        boolean resp=false;
        MyFactory mf = new MyFactory();
        Session s = mf.getSf().openSession();
        try{
            Transaction tx = s.beginTransaction();
            usu.setIdUsuario(id); 
            usu.setUsuModifUsuario(usuActivo);
            usu.setFecModifUsuario(new Date());
            usu.setActivo(false);
            s.update(usu);
            tx.commit();
            resp=true;
        }
        catch(Exception e){
            throw new Exception("Error: " + e.getMessage());
        }  
        finally{
            s.close();
            mf.getSf().close();
        }
        
        return resp;
    }
    
    /**
     * Permite verificar si un usuario ya existe.
     * @param usu {@code string} usuario que se desea verificar.
     * @return {@code boolean} true si existe y false si no existe.
     * @throws Exception {@code HibernateException} si no se pudo conectar u obtener datos de la base.
     */
    public boolean verificarUsuarioExistente(String usu) throws Exception{
        List<Usuario> usuarios =null;
        MyFactory mf = new MyFactory();
        Session s = mf.getSf().openSession();
        try {  
            usuarios = s.createCriteria(Usuario.class).list();
        }catch(Exception e){
            throw new Exception("Error: " + e.getMessage());
        }
        finally{
            s.close();
            mf.getSf().close();
        }
        
        Usuario temp = new Usuario();
        for(int i = 0;i < usuarios.size();i++){ 
            temp = (Usuario) usuarios.get(i);
            if(temp.getNomUsuario().equalsIgnoreCase(usu)){
                return true;
            }
            temp = null;
        }
        return false;
    }
    
    /**
     * Permite asignar un rol al usuario especificado.
     * @param usu {@code int} id del usuario al que se le asignará el rol.
     * @param rol {@code int} id del rol que se asignará al usuario.
     * @param usuAct {@code string} usuario activo en la aplicación.
     * @return {@code boolean} true si se pudo asignar el rol, false en caso contrario.
     * @throws Exception {@code HibernateException} si no se pudo conectar u obtener datos de la base.
     */
    public boolean asignarRolesAUsuario(int usu, int rol,String usuAct) throws Exception{
        boolean resp=false;
        MyFactory mf = new MyFactory();
        Session s = mf.getSf().openSession();
        try{
            Transaction tx = s.beginTransaction();
            Rolxusuario rxu=new Rolxusuario();
            RolxusuarioId id=new RolxusuarioId();
            id.setIdRol(rol);
            id.setIdUsuario(usu);
            rxu.setId(id);
            rxu.setActivo(true);
            rxu.setUsuCreacion(usuAct);
            rxu.setFecCreacion(new Date());
            rxu.setUsuModif(usuAct);
            rxu.setFecModif(new Date());
            s.save(rxu);
            tx.commit();
            resp=true;
        }
        catch(Exception e){
            throw new Exception("Error: " + e.getMessage());
        }  
        finally{
            s.close();
            mf.getSf().close();
        }
        return resp;
    }
    
    /**
     * Se encarga de retornar uno y solo un usuario, dado su identificador numerico
     * @param idUsr {@code int} identificador numerico
     * @return {@code Usuario} el usuario encontrado, o un usuario vacío con id = 0 si no se encuentra
     * @throws Exception {@code HibernateException} si no se pudo conectar u obtener datos de la base.
     */
    public Usuario obtenerUsuarioPorId(int idUsr) throws Exception {
        MyFactory mf = new MyFactory();
        Session s = mf.getSf().openSession();

        Usuario temp = null;
        try{
            temp = (Usuario)s.createCriteria(Usuario.class).add(Restrictions.eq("idUsuario", new Integer(idUsr))).uniqueResult();
        } 
        catch(Exception e){
            throw new Exception("Error: " + e.getMessage());
        } 
        finally {
            s.close();
            mf.getSf().close();
        }
        if(temp==null){
            temp = new Usuario();
            temp.setIdUsuario(0);
        }
        
        return temp;
    }
	
    /**
     * Permite eliminar todos los roles que tiene asignados el usuario.
     * @param idUsu {@code int} id del usuario
     * @return {@code boolean} true si pudo eliminar todo y false si ocurrió algún error
     * @throws Exception 
     */
    public boolean eliminarRolesDeUsuario(int idUsu) throws Exception{
        boolean resp=false;
        List<Rolxusuario> rxu =null;
        MyFactory mf = new MyFactory();
        Session s = mf.getSf().openSession();
        
        try {  
            rxu = s.createCriteria(Rolxusuario.class).add(Restrictions.eq("id.idUsuario", new Integer(idUsu))).list();
            Rolxusuario temporal = new Rolxusuario();
            Transaction tx = s.beginTransaction();
            for(int i = 0;i < rxu.size();i++){ 
                temporal = (Rolxusuario) rxu.get(i);
                s.delete(temporal);
            }
            tx.commit();
            resp=true;
        }catch(Exception e){
            throw new Exception("Error: " + e.getMessage());
        }  
        finally{
            s.close();
            mf.getSf().close();
        }
        
        return resp;
    }
}
